from flask import Flask, request, jsonify
from werkzeug.datastructures import ImmutableMultiDict
import pymongo
import time
import hashlib
import random
import numpy as np
import tushare as ts
ts.set_token("9e5b8a4de8126bc3012bb283adb493b113e5ecac8b942cf07f93585b")
from qcloudsms_py import SmsSingleSender
from qcloudsms_py.httpclient import HTTPError
from mongo_config import *

# mongo_client = pymongo.MongoClient(MONGO_URL, 27017)
mongo_client = pymongo.MongoClient(MONGO_URL, 27017)
db = mongo_client[MONGO_DB_RES]
appid = 1400207315
appkey = "82922343b194b2f445f44aaf04ec840d"
template_id = 323066
sms_sign = ""
pro = ts.pro_api()

app = Flask(__name__)

def ver_login(token):
    collection = [i['token'] for i in db['login'].find({}, {'_id': 0, 'token': 1})]
        # if type(token) == list and len(token) > 0:
        # for tk in token:
        #     if token in collection:
        #         return True
        #     else:
        #         return False
    if token in collection:
        return True
    else:
        return False

def select_token(token):
    collection = [i for i in db['login'].find({'token':token}, {'_id': 0, 'user_id': 1})]
    phone = collection[0]['user_id']
    tokens = [i['token'] for i in db['login'].find({'user_id': phone}, {'_id': 0, 'token': 1})]
    return tokens

# 向target中查询策略列表
def get_strategy_list(user_ids):
    baseline_dict = {'000300' : '沪深300', '000016' : '上证50' , '399905' : '中证500'}
    collection = [i for i in db['target'].find({'_id': {"$in": user_ids}}, {'_id': 1, 'strategy_name': 1, 'stock_pool': 1, 'profit_lb': 1,
                                                    'splitsize': 1, 'baseline': 1, 'marketvalue': 1}).limit(8)]
    # 获取策略收益表中的年收益
    profit_year = {i['_id'] : round(i['profit_year'] * 100, 2) for i in db['targetres'].find({'_id': {"$in": user_ids}},{'_id': 1, 'profit_year': 1})}
    # 将计算出的收益率添加到策略列表中
    for coll_single in collection:
        coll_single.pop('stock_pool')
        try:
            coll_single['profit_year_reality'] = profit_year[coll_single['_id']]
            coll_single['baseline'] = baseline_dict[coll_single['baseline']]
            # print(coll_single)
        except Exception as ex:
            print(ex)
    collection_count = db['target'].find({'_id': {"$in": user_ids}}).count()
    return collection, collection_count

# 获取策略列表
@app.route('/api/strategylist/', methods=['POST'])
def strategylist():
    if request.method == 'POST':
        token = request.headers['token']
        # page = request.form['page']
        flag = ver_login(token)
        tokens = select_token(token)
        if flag == True:
            strategylist, strategycount = get_strategy_list(tokens)
            if len(strategylist) != 0:
                return jsonify({'status': '200', 'strategylist': strategylist, 'strategycount': strategycount})
            else:
                return jsonify({'status': '200'})
        elif flag == False:
            return jsonify({'status': '401', 'progress': 'not login'})

# 删除策略
@app.route('/api/deletestrategy/', methods=['POST'])
def deletestrategy():
    strategy_id = request.form  # 策略id
    strategy_ids = strategy_id.getlist('strategy_id')
    # print(strategy_id.getlist('strategy_id'))
    # strategy_ids.append(strategy_id)
    # print(strategy_id, strategy_ids)
    # for strategy_id in strategy_ids:
    # flag = ver_login(strategy_id)
    # if flag == True:
    #     print(strategy_id)
    myquery = {"_id": {"$in":strategy_ids}}
    # 删除策略
    delres = db['target'].delete_many(myquery)
    delres_targetres = db['targetres'].delete_many(myquery)
    return jsonify({'status': '200', 'delete_count': delres.deleted_count})
    # elif flag == False:
    #     return jsonify({'status': '401', 'progress': 'not login'})

def submit_target_data(user_id, strategy_name, stock_pool, profit_lb, splitsize, baseline, marketvalue):
    dicts = {}
    dicts['_id'] = user_id
    dicts['strategy_name'] = strategy_name
    dicts['stock_pool'] = stock_pool
    dicts['profit_lb'] = float(profit_lb)
    dicts['splitsize'] = float(splitsize)
    dicts['baseline'] = baseline
    dicts['marketvalue'] = float(marketvalue)
    # dicts['stocks'] = stocklist
    try:
        db['target'].insert(dicts)
    except Exception as bwe:
        print(bwe.details)

# 提交目标收益等参数
@app.route('/api/target/', methods=['POST'])
def target():
    stk_pool_dict = {'hs300':hslist, 'sz50':stocklist, 'zz500':zzlist}
    # baseline_dict = {'hs300':'000300_SH', 'sz50':'000016_SH', 'zz500':'399905_SZ'}
    baseline_dict = {'hs300':'000300', 'sz50':'000016', 'zz500':'399905'}
    if request.method == 'POST':
        user_id = request.headers['token']  #token
        flag = ver_login(user_id)
        if flag == True:
            strategy_name = request.form['strategy_name']#策略名称
            stock_pool = request.form['stock_pool']  # 股票池
            if str(stock_pool) in stk_pool_dict.keys():
                stock_pool = stk_pool_dict[stock_pool]
            else:
                stock_pool = stocklist
            profit_lb = request.form['profit_lb']        #年化
            splitsize = request.form['splitsize']        #切割份数
            baseline = request.form['baseline']          #基准
            if str(baseline) in baseline_dict.keys():
                baseline = baseline_dict[baseline]
            marketvalue = request.form['marketvalue']    #资金
            print(user_id, strategy_name, stock_pool, profit_lb, splitsize, baseline, marketvalue)
            # 将用户提交的数据存储到数据库
            submit_target_data(user_id, strategy_name, stock_pool, profit_lb, splitsize, baseline, marketvalue)
            return jsonify({'status': '200'})
        elif flag == False:
            return jsonify({'status': '401', 'progress': 'not login'})

def get_stk_all(user_id, page, pagesize):
    collection = [i for i in db['targetres'].find({'_id': user_id},
                                                  {'_id': 0, 'profit_year': 1, 'profit_month': 1, 'profit_week': 1,
                                                   'profit_day': 1, 'profit_all': 1, 'stock_profit': 1,
                                                   'marketvalue': 1}).limit(pagesize).skip((page - 1) * pagesize)]
    collecion_count = [i['stock_profit'] for i in db['targetres'].find({'_id': user_id}, {'stock_profit': 1,})][0]
    marketvalue = float(collection[0]['marketvalue'])
    stocks_price = {i['_id']:i for i in mongo_client['stock_data']['details'].find({},{'_id':1, 'name':1, 'trade':1})}
    start = (page - 1) * pagesize
    end = page * pagesize - 1
    if len(collection) != 0:
        stock_profit = collection[0]['stock_profit'][start:end]
        stk_weight = []
        for stk in stock_profit:
            # print(stk)
            dicts = {}
            dicts['code'] = stk['code']
            dicts['name'] = stocks_price[stk['code']]['name']
            dicts['weight'] = round(float(stk['weight']) * 100, 2)
            dicts['hands'] = marketvalue * float(stk['weight']) / float(stocks_price[stk['code']]['trade'])
            stk_weight.append(dicts)
        return stk_weight, len(collecion_count)

# 获取股票占比
@app.route('/api/stkall/', methods=['POST'])
def stkall():
    if request.method == 'POST':
        user_id = request.headers['token']
        page = request.form['page']
        pagesize = request.form['pageSize']
        print(page, pagesize)
        flag = ver_login(user_id)
        if flag == True:
            # 向targetres中查询结果
            plate_data, count = get_stk_all(user_id, int(page), int(pagesize))
            # 计算中
            if len(plate_data) > 0:
                return jsonify({'status': '200', 'proportion': plate_data, 'count':count})
            else:
                return jsonify({'status': '202', 'progress': 'calculating'})
        elif flag == False:
            return jsonify({'status': '401', 'progress': 'not login'})

# 收益曲线
def profit_curve(user_id, stock_profit):
    baseline_dict = {'000300': 'hs300', '000016': 'sz50', '399905': '399905'}
    collection = [i for i in db['target'].find({'_id': user_id}, {'baseline': 1})][0]['baseline']
    # print(collection, len(collection))
    df = ts.get_k_data(baseline_dict[collection])[['close']]
    index_pro = []
    for index, datum in df.iterrows():
        index_pro.append(datum['close'])
    result = {}
    result['profit'] = stock_profit[::-1]
    result['index'] = [i/ index_pro[-len(stock_profit):-len(stock_profit)+1][0] for i in index_pro[-len(stock_profit):]]
    return result


# 获取之前提交的股票策略数据,并进行各项指标计算
@app.route('/api/stkdetail_curve/', methods=['POST'])
def stkdetail_curve():
    if request.method == 'POST':
        user_id = request.form['strategy_id']
        print(user_id)
        flag = ver_login(user_id)
        if flag == True:
            # 向targetres中查询结果
            collection = [i for i in db['targetres'].find({'_id': user_id},
                                                          {'_id': 0, 'profit_year': 1, 'profit_month': 1,
                                                           'profit_week': 1,
                                                           'profit_day': 1, 'profit_all': 1, 'stock_profit': 1,
                                                           'marketvalue': 1})]
            # print(collection)
            if len(collection) != 0:
                curve_profit_all = collection[0]['profit_all']
                plate_data = profit_curve(user_id, curve_profit_all)
                # 计算中
                if plate_data == None:
                    return jsonify({'status': '202', 'progress': 'calculating'})
                else:
                    return jsonify({'status': '200', 'progress': 'ok', 'profit_curve': plate_data})
        elif flag == False:
            return jsonify({'status': '401', 'progress': 'not login'})

# 向targetres中查询策略计算结果
def get_profit(user_id):
    result = {}
    backtest_cycle = '1y'
    collection = [i for i in db['targetres'].find({'_id': user_id},{'_id': 0, 'profit_year': 1, 'profit_month': 1, 'profit_week': 1,
                                                   'profit_day': 1, 'profit_all': 1, 'stock_profit': 1, 'marketvalue': 1})]
    if len(collection) != 0:
        compoer_profit_all = collection[0]['profit_all']
        year_profit = collection[0]['profit_year']
        marketvalue = collection[0]['marketvalue']
        sgarp_profit_all = np.array(compoer_profit_all)
        # 夏普率
        dayr = (sgarp_profit_all[1:] - sgarp_profit_all[:-1]) / sgarp_profit_all[:-1]
        exre = dayr - 0.04 / 250
        sharp = np.sqrt(250) * np.mean(exre) / np.std(exre)
        # max loss
        max_loss = round((compoer_profit_all[0] / max(compoer_profit_all)) * 100, 2)
        max_backtest = max_loss
        # print('最大亏损: ', max_loss)
        # continuity loss
        max_loss_count = 0
        first = 0
        loss_count = []
        for i in reversed(compoer_profit_all):
            # print(i)
            if i < first:
                max_loss_count += 1
                first = i
            else:
                loss_count.append(max_loss_count)
                max_loss_count = 0
                first = i
        # print('连续亏损: ', sum(loss_count))
        result['year_profit'] = year_profit
        result['marketvalue'] = marketvalue
        result['sharp'] = sharp
        result['max_backtest'] = max_backtest
        result['backtest_cycle'] = backtest_cycle
        result['max_loss'] = max_loss
        result['loss_count'] = sum(loss_count)
    else:
        result = None
    return result

# 获取之前提交的股票策略数据,并进行各项指标计算
@app.route('/api/stkdetail/', methods=['POST'])
def stkdetail():
    if request.method == 'POST':
        user_id = request.form['strategy_id']
        print(user_id)
        flag = ver_login(user_id)
        if flag == True:
            # 向targetres中查询结果
            plate_data = get_profit(user_id)
            # 计算中
            if plate_data == None:
                return jsonify({'status': '202', 'progress': 'calculating'})
            else:
                return jsonify({'status': '200', 'progress': 'ok', 'profit': plate_data})
        elif flag == False:
            return jsonify({'status': '401', 'progress': 'not login'})

def verification_code(phone, code, token):
    collection = db['user']
    collection_login = db['login']
    coll_list = [i for i in collection.find({'_id':phone})]
    if len(coll_list) > 0:
        if coll_list[0]['code'] == code:
            collection.update_one({'_id': phone}, {"$set": {'status': '1'}})
            try:
                # collection_login.remove({'_id':phone})
                collection_login.insert({'user_id':phone, 'code':code, 'token':token})
            except Exception as e:
                print(e)
            return True
        else:
            return False

@app.route('/api/get_verification_code/', methods=['POST'])
def get_verification_code():
    if request.method == 'POST':
        user_id = request.form['user_id']
        code = request.form['verification_code']
        flag = bytes(str(user_id) + str(code) + str(int(time.time())), encoding="utf8")
        token = hashlib.md5(flag).hexdigest()
        ver_flag = verification_code(str(user_id), str(code), token)
    if ver_flag == True:
        return jsonify({'status':'200', 'token': token, 'tel':user_id})
    else:
        return jsonify({'status':'403', 'msg':'verification code error'})

def register_user(phone, code):
    collection = db['user']
    try:
        dicts = {}
        dicts['_id'] = str(phone)
        dicts['code'] = str(code)
        # dicts['register_time'] = str(int(time.time()) + 24*60*60)
        dicts['status'] = str(0)
        if collection.find({'_id': str(phone)}).count() > 0:
            collection.remove({'_id': str(phone)})
        collection.insert(dicts)
    except Exception as e:
        print(e)

@app.route('/api/register/', methods=['POST'])
def register():
    if request.method == 'POST':
        user_id = request.form['user_id']
        phone_numbers = [str(user_id)]
        ssender = SmsSingleSender(appid, appkey)
        verification_code = str(random.randint(100000, 999999))
        params = [verification_code, '3']  # 当模板没有参数时，`params = []`
        try:
            result = ssender.send_with_param(86, phone_numbers[0], template_id, params, sign=sms_sign, extend="", ext="")
        except HTTPError as e:
            print(e)
        except Exception as e:
            print(e)
        register_user(user_id, verification_code)
        return jsonify({'status': '200', 'verification_code': verification_code})

if __name__ == '__main__':
    # app.run(debug=True)
    app.run(debug=True, host = '0.0.0.0')